﻿//#region 1 :Apply , call 的用法-------------------------------------------------------------------------------------------
// 先创建两个变量
//例子1:
function AObj() {
    this.AMethod = function () {
        alert('this is A"s Obj');
    }
}


function BObj() {
    this.bValue = 'Default value';
    this.setValue = function (msg) {
        this.bValue = msg;
    };
    this.BMethod = function () {
        alert(this.bValue);
    }
} 
//通过调用别人的方法来达到自己的目的, 别人的方法我没有, 我借来用
var newA = new AObj();
var newB = new BObj();
newB.setValue.call(newA, 'what hell');
newB.BMethod.call(newA);
//输出: what hell

//例子2:
function A(name, age) {
    this.name = name;
    this.age = age;
    this.alertName = function () {
        alert(this.name);
    }
}

function B(name, age, sex) {
    A.apply(this, arguments); // A.Call(this,name,age);
    this.sex = sex;
    this.alertSex = function () {
        alert(this.sex);
    }
}
var test = new B('名字', 20, '男');
test.alertName();
//输出: 名字
//这样B这个类就继承A这个类了, B实例化出来的对象就有了跟A一样的东西(方法,变量), 相当于B是从A继承来的
//apply的意思是把..应用于, 意思就是 我要把A的一切应用于B, 让B拥有A的一切, 实际上, Apply和Call都有对象模拟的意思
//以B的对象去调用A的构造函数, 自然通过A中this的指向会把B的对象中也相应的添加上A的那些属性和方法, 
//主要作用就是通过这个方法来实现继承, 否则怎么面向对象? 参考<Javascript高级程序设计>中相应段, 
//理解了对象复制就明白Apply和Call了

//结论: call, apply作用就是借用别人的方法来调用,就像调用自己的一样
//关系: foo.call(this, arg1, arg2, arg3) == foo.apply(this, arguments) == this.foo(arg1, arg2, arg3)
//另外, 在call里传入参数是null或者undefined时,他会把传入参数当成window或者global
//#endregion

//#region 2:关于prototype
//理解1:
//prototype 是对象, 而下面的ObjA是函数, 用typeof打出来能看到
//prototype 只能是类(或函数, 一说类型. 包括: Array, Boolean, Date, Enumerator, Error, Function, Number, Object, RegExp, String)的属性, 而对象的属性用__proto__来查看
//一个对象的constructor是它的构造函数的prototype.constructor，而每一个函数都有一个prototype，默认情况下，这个prototype有一个constructor属性，
//指向的是它自己。
function ObjA() {
    this.name = "ObjA";
}

ObjA.prototype.constructor = function () {
    this.id = "ObjA's ID";
}
var insA = new ObjA();

//alert(insA.constructor);


function Father() {
    this.age = 55;
    this.name = 'Father';
}
Father.prototype.money = 100;

var fat = new Father();
alert(fat.money);
//理解: 首先Java要求类必须被编译成字节码才能被载入虚拟机，而JavaScript是在运行
//代码的同时，执行了类似Java的编译载入的过程。并且Java的类在载入虚拟机
//后一般就不能再改变类的定义了，比如把一个方法的行为改变或指向另一个方
//法的引用等。而JavaScript在运行期还可以通过prototype来改变类及所有该类生成
//的对象的行为。例如上面的例子中，在解析完function A的函数体后，整个类也
//就生成了，这时候如果new的话就能得到类的实例，紧接着的代码又向类动态
//添加了新的行为。

//而在function A的函数体内定义的this成员，可以理解为‘后’绑定成员。 
//可以这么理解，在new A()的时候JavaScript建立了一个临时对象， 
//把A.prototype的所有成员复制到临时对象中，然后再把函数A中 
//定义的this成员也绑定到临时对象中，然后把临时对象返回给用户

//prototype就是在函数定义后再对其模板进行一次补充, 在new函数之后先把prototyep里的东西拷贝到临时变量中,
//然后再进行原函数的构造, 所以在new之后对prototype进行的任何操作都不会改变已经new出来的对象.
//最后再谈谈prototype的constructor成员，该成员是对一个类的构造
//函数的引用，在类定义的初期，如果一个类没有从其他别的类那
//里继承，该类的prototype.constructor属性保存的是该类自身的引用，
//如果该类从别的类继承，那么它的constructor属性就保存了父类的
//constructor引用，一般constructor没有什么用处，但可以通过它来取
//得他的类的信息，就像Java里的对象都有getClass()方法，constructor
//就是干这个用的。有它的好处是，再运行期可以改变所有同类对象
//的成员行为，如：

// someObj.constructor.prototype.somePrototype = function () { 
// other process . 
// } 
//因此好的习惯是在继承之后把prototype的constructor成员设置一下， 
//否则会把父类的prototype成员改掉，那样程序的行为就不可预知了。 
//如：

// function classA() { 
// } 
// 
// classB.prototype = new classA(); 
// classB.prototype.constructor = classB; 

//Reference : http://www.blogjava.net/sterning/archive/2009/04/26/267583.html

//理解2:
//——理解原型、构造函数（类）、对象的关系
//《Javascript王者归来》一书中打了个很贴切的比方，习语有“照猫画虎”，可以理解为“照着‘某只猫’画出一类虎”，那么由这类虎构造的具体的‘某只虎’也就继承了这只猫的所有属性。这里的“某只猫”就是原型，而“虎”就是类型（构造函数）。那么具体的“某只虎”就是构造函数“虎”的一个对象实例。 
//用Js代码表示就是：“虎.prototype=某只猫”或“虎.prototype=new 猫()”、“某只虎=new 虎()”、“某只虎.prototype=某只猫”。
//概念化：
//所有的构造函数都有一个prototype属性。当函数被定义的时候，prototype属性自动创建和初始化，初始化值是一个对象。这个原型对象只带有一个属性constructor，它指回到和原型相关联的那个构造函数（这也就是每个对象都有一个constructor属性的原因）。
//添加给这个原型的任何一个属性，都会成为对应构造函数创建的对象的属性。即对象从它的原型那里继承属性。
// 
//2、prototype的特性
//原型模式（prototype pattern）要求 一个类型（这里指构造函数）一个时刻只能有一个原型。
//这个类型（构造函数）的所有实例（对象），必须满足原型关系的类型链。
//Reference : http://www.cnblogs.com/gppblog/archive/2010/01/20/1652091.html


//理解3:
//1:prototype属性是只有constructor才有的属性, object没有
//2:__proto__是每个对象都含有的一个属性, 虽然是隐式的, 某些浏览器不能查看(ie?). 对于实例化出来的对象, 它的__proto__指向的是其构造函数的prototype属性, 注意, 是每个对象都有的属性, 所以
//constructor也是有这个属性的, 如sfoo.constructor.__proto__ === Function.prototype //output true, 所以不需要去注意或者特意区分__proto__是什么, 想知道__proto__是什么就看这个对象
//的构造函数的prototype属性是什么就可以了.
//3:__proto__和prototype之间的关系仅仅限于__proto__指向的是其构造函数的prototype属性, 除此之外, 二者没什么联系
//4:prototype存在的意义, prototype是为了在js中实现面向对象的继承所引用的, 所以它的意义必然在此, 它就是在你的构造函数中单独开辟了一个区间, 用来记录你这个类(构造函数)所在的关系链(原型链), 你想
//记录某个类的继承关系, 或者说有哪些是继承的内容, 必然在构造函数中保存(不会在实例中保存), prototype的存在就是如此, 每个构造函数都含有这个对象, 既然这个对象是保存继承关系的, 而且js中对象的最根基类
//都是Object对象, 所以如果一个类(构造函数), 没有其他的继承关系, 那么他的prototype指向Object.
//prototype内部什么样呢? 如下:
//prototype : {
//    constructor : function(){}
//    __proto__ : Object
//}
//可以看到,prototype就是通过__proto__这个链条去上级一层层查找方法和属性的, 而到达最根节点Object时, 就指向的是Object的prototype, 也就是一堆最原始对象的合集,其实也是对象, 也就是
//SFoo.prototype.__proto__ === Object.prototype  //output true
//如果理解了js中任何东西都是对象, 就很好理解了, 对象! var a = {} 这就是对象!{}中随便你怎么处理, 怎么操作, 新增修改, 都可以,保存链接等等.
//对于prototype的继承, 如下代码:
var animal = function () { };
var tiger = function () { };
var a = new animal();
tiger.prototype = new animal();
//执行tiger.prototype = new animal();就完成了tiger从animal的继承, 因为对象的继承是从构造函数来的, 构造函数的继承是通过其内在prototype这个属性来实现的, prototype是通过这个对象自己的__proto__属性
//来向上查找的, 所以prototype原本是指向Object的, 里面2个属性->
//prototype : {
//    constructor : function(){}
//    __proto__ : Object
//}, 改变指针之后指向了animal的对象, 那么animal的对象中有什么呢? 有一些animal自己的东西( 这个例子是空) , 剩下的一个隐藏的东东就比较重要了: __proto__!!!!, 最关键就是这个, 继承就要这个东东, 这个隐藏
//的小东东, 有了这个就等于是链上了animal这条线, 可以找到animal任何以前有过的东西(原型链查找)
//实现最原始的继承方法:
function Animal() { }
function Tiger() { }
Tiger.prototype = new Animal()
Tiger.prototype.constructor = Tiger
//这样Tiger就继承自Animal了, 问题是为什么Tiger.prototype = new Animal() 之后要把原型的constructor指向Tiger呢, 这是因为标准的prototype属性是两个对象的集合, 参考上方prototype内部结构,
//所以当把prototype指向Animal的对象, 让其有了__proto__属性之后, 还需要把constructor属性添加回去(不然protototype就没有constructor这个属性了)
//5:当一个函数执行sfoo.constructor.prototype = new Foo();或者通过构造函数进行修改:
//SFoo.prototype=Foo.prototype 时,  sfoo的构造函数SFoo的prototype就被指向到Foo的什么???

//答:
//1:__proto__指向创建这个对象的构造函数的prototype属性
//ref:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/Proto
//2:according to https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object
//constructor:指的是创建对象原型的函数, 不是创建对象的函数
//!!!All objects inherit a constructor property from their prototype
//constructor是所有对象都有的属性, 而且是从prototype(这里的prototype是概念, 不是函数对象的prototype属性)继承下来的...当然constructor
//funcion && Function : 任何由function声明的函数都是Function这个类型的对象,并且拥有Function所有的内置属性和方法    
  
$(function () {
    var foo = new Foo(4, 5);

    var sfoo = new SFoo();
    sfoo.constructor.prototype = new Foo();
});

function Foo(xval,yval) {
    this.x = xval;
    this.y = yval;
    this.fun = function () {
        return this.x + this.y;
    }
}
function SFoo() { }
//待理解:
//constructor is a pre-defined [[DontEnum]] property of the object pointed to by the prototype property 
//of a function object and will initially point to the function object itself.
//__proto__ is equivalent to the internal [[Prototype]] property of an object, ie its actual prototype.

//When you create an object with the new operator, its internal [[Prototype]] property will be set to the 
//object pointed to by the constructor function's prototype property.

//This means that .constructor will evaluate to .__proto__.constructor, ie the constructor function used to create the object, 
//and as we have learned, the protoype property of this function was used to set the object's [[Prototype]].

//It follows that .constructor.prototype.constructor is identical to .constructor (as long as these properties haven't been overwritten); 
//see here for a more detailed explanation.

//If __proto__ is available, you can walk the actual prototype chain of the object. 
//There's no way to do this in plain ECMAScript3 because JavaScript wasn't designed for deep inheritance hierarchies.

//几点补充:
//1: var a = new String(); 
//a.__proto__ == a.constructor.prototype // true
//a.constructor == a.constructor.prototype.constructor // true
//对象(a)的__proto__属性其实就是其构造函数的prototype, 对象其实没有什么属性, 都是从其构造函数的prototype抄下来的
//constructor指的就是构造函数, prototype是构造函数的属性, 其他对象没有这个属性, 所以a.constructor其实指向的是a的构造函数的原型的constructor


//#endregion

//#region 3:关于编码(js和c#)
//reference:http://www.cnblogs.com/artwl/archive/2012/03/07/2382848.html
//Js 部分 :
//1:Escape(不推荐) 只能对ASCII符号正确编码 , escape不编码字符有69个：*，+，-，.，/，@，_，0-9，a-z，A-Z
//2:encodeURI：用于对网址编码(不包含参数), 由于encodeURI不对冒号(:)、斜杠(/)进行编码，所以如果参数(如把网址作为参数)中包含冒号(:)、斜杠(/)，就会解析出错，所以此方法不能对参数进行编码。
//3:encodeURIComponent:用于对网址参数进行编码,encodeURIComponent不编码字符有71个：!， '，(，)，*，-，.，_，~，0-9，a-z，A-Z,适合对URI中的参数进行编码
//C#部分:
//1:Server.UrlEncode && HttpUtility.UrlEncode:不推荐
//把这两个放到一起说是因为这两个方法在绝大多数情况下是一样的。它们的区别是HttpUtility.UrlEncode默认使用UTF8格式编码，而Server.UrlEncode是使用系统预设格式编码，
//Server.UrlEncode使用系統预设编码做为参数调用HttpUtility.UrlEncode编码，所以如果系统全局都用UTF8格式编码，这两个方法就是一样的。
//HttpUtility.UrlEncode对冒号(:)和斜杠(/)进行了编码，所以不能用来对网址进行编码。
//那么能不能对参数进行编码呢，答案也是否定的。因为在参数中空格应该被编码为%20而不是被HttpUtility.UrlEncode编码为加号(+)，所以不推荐用这两个方法对URI进行编码。
//2:Uri.EscapeUriString:用于对网址编码(不包含参数)
//类似JavaScript中的encodeURI方法。
//3:Uri.EscapeDataString:用于对网址参数进行编码
//类似JavaScript中的encodeURIComponent方法
//#endregion

//#region 4:闭包
//下方描述引用:http://news.cnblogs.com/n/134115/
//闭包就是:
//*函数的局部变量的集合, 只不过这些变量在函数返回后仍然存在
//*闭包就是就是函数的“堆栈”在函数返回后并不释放，我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配
//*当在一个函数内定义另外一个函数就会产生闭包
//Example 1:
function Example(name) {
    var text = 'hello, ' + name;
    return function () {
        alert(text); // or return text;
    }
}
var myobj = Example('jason');
myobj();

//Example 2:
function say667() {
    // Local variable that ends up within closure
    var num = 666;
    var sayAlert = function () {
        alert(num);
    }
    num++;
    return sayAlert;
}
var sayobj = say667();
sayobj()
//#endregion

//#region 5:关于undefined, null...未完
//js中定义了未赋值和未定义都为undefined如:
var a;
b;
//这里的a和b都是undefined

//#endregion

//#region 6:Ext学习参考
//ref:ExtJs中继承的实现与理解—extend  http://blog.csdn.net/jerrysbest/article/details/6639460
//ref:阅读Ext 学习Javascript（一）Core/Ext.js http://www.cnblogs.com/boolean/archive/2007/10/16/926490.html
//#endregion